﻿using NovoDataBase;
using NovoSerDes.Comm;
using NovoUSB2XXX;
using Sunny.UI.Win32;
using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using static NovoDataBase.RegisterMap;

namespace NovoSerDes
{
    public class SerDesComm
    {
        private int devID = -1;
        private byte currentDevAddr = 0x42 << 1;    //CH347 need a 8bits device address
        private static int totalDevCnt = 0;
        private IICMode defaultIICMode = IICMode.A16D32;
        private NOVO_IIC_CONFIG i2c_cfg = new NOVO_IIC_CONFIG
        {
            ClockSpeedHz = 1,
            EnablePu = 0
        };
        private INovoComm _novoComm;
        public SerDesComm()
        {
            _novoComm = new NovoCommWIthLog();
            //this.devID = _devID;
            int ret = NovoComm.Novo_CreateSdk();

            NOVO_DEV_CONFIG myDev = new NOVO_DEV_CONFIG();
            myDev.devType = NOVO_DEV_List.CH347;
            myDev.I2C_EN = true;
            myDev.SPI_EN = false;
            myDev.UART_EN = false;
            myDev.GPIO_EN = false;

            ret = NovoComm.Novo_InitDev(ref myDev);
            Console.WriteLine("Novo_InitDev result = {0}", ret);
            Debug.WriteLine("Test ");

            StringBuilder devName = new StringBuilder();
            NovoComm.Novo_GetDevName(devName);
            Console.WriteLine("Dev Name = {0}", devName);

            //ret = NovoComm.Novo_SetDeviceId(devID);
            //Console.WriteLine("Change Id to {0}, result ={0}", devID, ret);

            //ret = NovoComm.Novo_OpenDevice();
            //this.isOpen = ret == 0 ? true : false ;
            //Console.WriteLine("Novo_OpenDevice result ={0}", ret);

            //NOVO_DEV_INFO dEV_INFO = new NOVO_DEV_INFO();
            //ret = NovoComm.Novo_GetDevInfo(ref dEV_INFO);

            //NOVO_IIC_CONFIG i2c_cfg;
            //i2c_cfg.ClockSpeedHz = (UInt32)NOVO_IIC_Speed.IIC_100K;
            //i2c_cfg.EnablePu = 0;
            //ret = NovoComm.Novo_IIC_Init(ref i2c_cfg);
            //Console.WriteLine("Novo_IIC_Init: {0} \n", ret);
        }

        public int DevID
        {
            get { return devID; }
        }

        public int TotalDeviceCount
        {
            get { return totalDevCnt; }
        }

        private bool isOpen = false;

        public bool IsOpen
        {
            get { return this.isOpen; }
        }

        public NOVO_IIC_CONFIG I2C_CFG
        { get { return this.i2c_cfg; } }

        public string GetDevName()
        {
            StringBuilder devName = new StringBuilder();
            NovoComm.Novo_GetDevName(devName);

            return devName.ToString();
        }

        public bool OpenDevice(int _devID)
        {
            this.devID = _devID;
            int ret = NovoComm.Novo_CreateSdk();

            NOVO_DEV_CONFIG myDev = new NOVO_DEV_CONFIG();
            myDev.devType = NOVO_DEV_List.CH347;
            myDev.I2C_EN = true;
            myDev.SPI_EN = false;
            myDev.UART_EN = false;
            myDev.GPIO_EN = false;

            ret = NovoComm.Novo_InitDev(ref myDev);
            Console.WriteLine("Novo_InitDev result = {0}", ret);

            StringBuilder devName = new StringBuilder();
            NovoComm.Novo_GetDevName(devName);
            Console.WriteLine("Dev Name = {0}", devName);

            ret = NovoComm.Novo_SetDeviceId(devID);
            Console.WriteLine("Change Id to {0}, result ={0}", devID, ret);

            ret = NovoComm.Novo_OpenDevice();
            this.isOpen = ret == 0 ? true : false;
            Console.WriteLine("Novo_OpenDevice result ={0}", ret);

            ret = NovoComm.Novo_IIC_Init(ref i2c_cfg);
            Console.WriteLine("Novo_IIC_Init: {0} \n", ret);

            return ret == 0 ? true : false;
        }

        public bool SetDevID()
        {
            int ret = NovoComm.Novo_SetDeviceId(this.devID);
            return ret == 0 ? true : false;
        }

        public bool SetStretch(bool iEnable)
        {
            int ret = NovoComm.Novo_SetStretch(this.devID, iEnable);
            return ret == 1 ? true : false;
        }

        public bool ReOpenDevice()
        {
            //this.devID = _devID;
            int ret = NovoComm.Novo_CreateSdk();

            NOVO_DEV_CONFIG myDev = new NOVO_DEV_CONFIG();
            myDev.devType = NOVO_DEV_List.CH347;
            myDev.I2C_EN = true;
            myDev.SPI_EN = false;
            myDev.UART_EN = false;
            myDev.GPIO_EN = false;

            ret = NovoComm.Novo_InitDev(ref myDev);
            Console.WriteLine("Novo_InitDev result = {0}", ret);

            StringBuilder devName = new StringBuilder();
            NovoComm.Novo_GetDevName(devName);
            Console.WriteLine("Dev Name = {0}", devName);

            ret = NovoComm.Novo_SetDeviceId(devID);
            Console.WriteLine("Change Id to {0}, result ={0}", devID, ret);

            ret = NovoComm.Novo_OpenDevice();
            this.isOpen = ret == 0 ? true : false;
            Console.WriteLine("Novo_OpenDevice result ={0}", ret);

            ret = NovoComm.Novo_IIC_Init(ref i2c_cfg);
            Console.WriteLine("Novo_IIC_Init: {0} \n", ret);

            return ret == 0 ? true : false;
        }

        public bool CloseDevice()
        {
            if (NovoComm.Novo_CloseDevice() == 0)
            {
                this.isOpen = false;
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 7bits device address
        /// </summary>
        public byte CurrentDevAddr
        {
            set { this.currentDevAddr = (byte)(value << 1); }
            get { return (byte)(this.currentDevAddr >> 1); }
        }

        private byte[] DataToByteArray(object data, int byteCnt)
        {
            byte[] targetBuffer = new byte[byteCnt];

            if (byteCnt == 1)
            {
                targetBuffer[0] = Convert.ToByte(data);
            }
            else if (byteCnt == 2)
            {
                byte[] tempData = BitConverter.GetBytes(Convert.ToUInt16(data));
                for (int ix = 0; ix < byteCnt; ix++)
                    targetBuffer[ix] = tempData[1 - ix];
            }
            else if (byteCnt == 4)
            {
                // tempData array convert as little endian
                byte[] tempData = BitConverter.GetBytes(Convert.ToUInt32(data));
                for (int ix = 0; ix < byteCnt; ix++)
                    targetBuffer[ix] = tempData[3 - ix];
            }

            return targetBuffer;
        }

        private object ByteArrayToData(byte[] arr, int byteCnt)
        {
            if (byteCnt == 1)
                return (object)arr[0];

            byte[] tempArray = new byte[byteCnt];
            for (int ix = 0; ix < byteCnt; ix++)    // little endian to big endian
            {
                tempArray[ix] = arr[byteCnt - 1 - ix];
            }

            if (byteCnt == 2)   // Just use arr[0] and arr[1], and arr[1] used first
                return BitConverter.ToUInt16(tempArray, 0);
            else if (byteCnt == 4)
            {
                //for (int ix = 0; ix < byteCnt; ix++)    // little endian to big endian
                //{
                //    tempArray[ix] = arr[3 - ix];
                //}
                return BitConverter.ToUInt32(tempArray, 0);
            }
                
            else
                return 0;
        }

        #region IIC for Script

        public bool IICWrite(byte devAddr, object RegAddr, object RegData, IICMode i2cMode)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            int byteCnt_RegAddr = ((byte)i2cMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)i2cMode & 0x0F);

            byte[] wrBuffer = new byte[byteCnt_RegAddr + byteCnt_RegData + 1];

            wrBuffer[0] = devAddr;
            //byte[] tempBuffer = BitConverter.GetBytes((UInt32)RegAddr);
            byte[] tempBuffer = DataToByteArray(RegAddr, byteCnt_RegAddr);
            Array.Copy(tempBuffer, 0, wrBuffer, 1, byteCnt_RegAddr);

            //tempBuffer = BitConverter.GetBytes((UInt32)RegData);
            tempBuffer = DataToByteArray(RegData, byteCnt_RegData);
            Array.Copy(tempBuffer, 0, wrBuffer, byteCnt_RegAddr + 1, byteCnt_RegData);

            //return (NovoComm.Novo_IIC_RW_U8_Basic(devAddr, wrBuffer, wrBuffer.Length, null, 0) == 0) ? true : false;
            return (_novoComm.Novo_IIC_RW_U8_Basic(devAddr,wrBuffer,wrBuffer.Length,null,0) == 0) ? true : false;
        }

        public bool IICRead(byte devAddr, object RegAddr, out object RegData, IICMode i2cMode)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            int byteCnt_RegAddr = ((byte)i2cMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)i2cMode & 0x0F);

            byte[] wrBuffer = new byte[byteCnt_RegAddr + 1];
            byte[] rdBuffer = new byte[(byteCnt_RegData + 3) / 4 * 4];  //Buffer size should be 4x for UInt32 convert.

            wrBuffer[0] = devAddr;
            //byte[] tempBuffer = BitConverter.GetBytes((UInt32)RegAddr);
            byte[] tempBuffer = DataToByteArray(RegAddr, byteCnt_RegAddr);
            Array.Copy(tempBuffer, 0, wrBuffer, 1, byteCnt_RegAddr);

            //int ret = NovoComm.Novo_IIC_RW_U8_Basic(devAddr, wrBuffer, wrBuffer.Length, rdBuffer, byteCnt_RegData);
            
            int ret = _novoComm.Novo_IIC_RW_U8_Basic(devAddr, wrBuffer, wrBuffer.Length, rdBuffer, byteCnt_RegData);
            if (ret == 0)
            {
                RegData = ByteArrayToData(rdBuffer, byteCnt_RegData);
                return true;
            }
            else
            {
                RegData = 0;
                return false;
            }
        }

        public bool IICWrite_Burst(byte devAddr, object RegAddr, object[] RegData, IICMode i2cMode)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            int byteCnt_RegAddr = ((byte)i2cMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)i2cMode & 0x0F) * RegData.Length;
            int byteCnt_PerData = (byte)i2cMode & 0x0F;

            byte[] wrBuffer = new byte[byteCnt_RegAddr + byteCnt_RegData + 1];
            wrBuffer[0] = devAddr;

            //byte[] tempBuffer = BitConverter.GetBytes((UInt32)RegAddr);
            byte[] tempBuffer = DataToByteArray(RegAddr, byteCnt_RegAddr);
            Array.Copy(tempBuffer, 0, wrBuffer, 1, byteCnt_RegAddr);

            for (int ix = 0; ix < RegData.Length; ix++)
            {
                //tempBuffer = BitConverter.GetBytes((UInt32)RegData[ix]);
                tempBuffer = DataToByteArray(RegData[ix], byteCnt_PerData);
                Array.Copy(tempBuffer, 0, wrBuffer, 1 + byteCnt_RegAddr + ix * byteCnt_PerData, byteCnt_PerData);
            }

            return (NovoComm.Novo_IIC_RW_U8_Basic(devAddr, wrBuffer, wrBuffer.Length, null, 0) == 0) ? true : false;
        }

        public bool IICRead_Burst(byte devAddr, object RegAddr, out object[] RegData, int readCnt, IICMode i2cMode)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            int byteCnt_RegAddr = ((byte)i2cMode >> 4) & 0x0F;
            int byteCnt_RegData = ((byte)i2cMode & 0x0F) * readCnt;
            int byteCnt_PerData = (byte)i2cMode & 0x0F;
            RegData = new object[readCnt];

            byte[] wrBuffer = new byte[byteCnt_RegAddr + 1];
            byte[] rdBuffer = new byte[(byteCnt_RegData + 3) / 4 * 4]; //Buffer size should be 4x for UInt32 convert.

            wrBuffer[0] = devAddr;
            //byte[] tempBuffer = BitConverter.GetBytes((UInt32)RegAddr);
            byte[] tempBuffer = DataToByteArray(RegAddr, byteCnt_RegAddr);
            Array.Copy(tempBuffer, 0, wrBuffer, 1, byteCnt_RegAddr);

            int ret = NovoComm.Novo_IIC_RW_U8_Basic(devAddr, wrBuffer, wrBuffer.Length, rdBuffer, byteCnt_RegData);

            if (ret == 0)
            {
                for (int ix = 0; ix < readCnt; ix++)
                {
                    RegData[ix] = ByteArrayToData(rdBuffer.Skip(ix * byteCnt_PerData).Take(byteCnt_PerData).ToArray(), byteCnt_PerData);

                    //if(byteCnt_PerData == 1)
                    //    RegData[ix] = (object)rdBuffer[ix];
                    //else if(byteCnt_PerData == 2)
                    //    RegData[ix] = (object)BitConverter.ToUInt16(rdBuffer.Skip(ix * byteCnt_PerData).Take(byteCnt_PerData).ToArray(), 0);
                    //else if(byteCnt_PerData == 4)
                    //    RegData[ix] = (object)BitConverter.ToUInt32(rdBuffer.Skip(ix * byteCnt_PerData).Take(byteCnt_PerData).ToArray(), 0);
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        #endregion IIC for Script

        #region I2C for Regmap UI

        public bool IICWrite(byte devAddr, UInt16 RegAddr, UInt32 RegData)
        { return false; }

        //public bool IICWrite(UInt32 RegAddr, UInt32 RegData)
        //{ return false; }

        public bool IICWrite(UInt32 RegAddr, UInt32 RegData)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            //return NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, (UInt16)(RegAddr), RegData) == 0 ? true : false;
            return _novoComm.Novo_IIC_Wr_U16U32(currentDevAddr,(UInt16)(RegAddr),RegData) == 0 ? true : false;
        }

        public bool IICWrite(UInt32 RegAddr, UInt32 RegData, UInt32 startBit, UInt32 endBit)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            //IICSetBitField RegAddr [x:y] Value;
            // Parameter sequence: RegAddr EndBitIndex StartBitIndex BFValue
            UInt32 rdData = 0;
            UInt32 wrData = 0;
            int ret = NovoComm.Novo_IIC_Rd_U16U32(this.currentDevAddr, (UInt16)RegAddr, ref rdData);
            if (ret != 0)
            {
                return false;
            }

            //Console.WriteLine(string.Format("IIC Read: Reg0x{0} = 0x{1}", RegAddr.ToString("X2"), rdData.ToString("X2")));

            UInt32 bfMask = (UInt32)(Math.Pow(2, endBit + 1) - Math.Pow(2, startBit));

            //Console.WriteLine(((1 << (int)(endBitIx + 1)) - 1).ToString("X2"));
            //Console.WriteLine(((1 << (int)startBitIx) - 1).ToString("X2"));

            //Console.WriteLine(((UInt32)(Math.Pow(2, endBitIx + 1) - 1)).ToString("X2"));
            //Console.WriteLine(((UInt32)(Math.Pow(2, startBitIx) - 1)).ToString("X2"));

            wrData = (rdData & ~bfMask) | ((RegData << (int)startBit) & bfMask);
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, (UInt16)RegAddr, wrData);
            if (ret != 0)
            {
                return false;
            }
            //Console.WriteLine(string.Format("IIC Write: Reg0x{0} = 0x{1}; BF Mask: 0x{2}", RegAddr.ToString("X2"), wrData.ToString("X2"), bfMask.ToString("X2")));

            return true;
        }

        public bool IICWrite_Burst(byte devAddr, UInt16 RegAddr, UInt32[] RegData, int count)
        { return false; }

        public bool IICRead(byte devAddr, UInt32 RegAddr, out UInt32 RegData)
        {
            RegData = 0;
            return false;
        }

        public bool IICRead(UInt32 RegAddr, out UInt32 RegData)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            RegData = 0;
            //int ret = NovoComm.Novo_IIC_Rd_U16U32(currentDevAddr, (UInt16)(RegAddr), ref RegData);
            int ret = _novoComm.Novo_IIC_Rd_U16U32(currentDevAddr, (UInt16)(RegAddr), ref RegData);
            return (ret == 0) ? true : false;
        }

        public bool IICRead(UInt32 RegAddr, out UInt32 RegData, UInt32 startBit, UInt32 endBit)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            RegData = 0;
            //int ret = NovoComm.Novo_IIC_Rd_U16U32(currentDevAddr, (UInt16)(RegAddr), ref RegData);

            //return (ret == 0) ? true : false;

            UInt32 rdData = 0;
            UInt32 bfValue = 0;
            int ret = NovoComm.Novo_IIC_Rd_U16U32(this.currentDevAddr, (UInt16)RegAddr, ref rdData);
            if (ret != 0)
            {
                return false;
            }

            //Console.WriteLine(string.Format("IIC Read: Reg0x{0} = 0x{1}", RegAddr.ToString("X2"), rdData.ToString("X2")));

            UInt32 bfMask = (UInt32)(Math.Pow(2, endBit + 1) - Math.Pow(2, startBit));

            //Console.WriteLine(((1 << (int)(endBitIx + 1)) - 1).ToString("X2"));
            //Console.WriteLine(((1 << (int)startBitIx) - 1).ToString("X2"));

            //Console.WriteLine(((UInt32)(Math.Pow(2, endBitIx + 1) - 1)).ToString("X2"));
            //Console.WriteLine(((UInt32)(Math.Pow(2, startBitIx) - 1)).ToString("X2"));
            bfValue = (UInt32)((Convert.ToUInt32(rdData) & bfMask) >> (int)startBit);
            RegData = bfValue;


            //Console.WriteLine(string.Format("IIC Read: Reg0x{0} = 0x{1}; BF Mask: 0x{2}\r\n",
            //    RegAddr.ToString("X2"), rdData.ToString("X2"), bfMask.ToString("X2")));

            return true;
        }
        public bool IICRead(byte devAddr, UInt32 RegAddr, out UInt32 RegData, UInt32 startBit, UInt32 endBit)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            RegData = 0;
            //int ret = NovoComm.Novo_IIC_Rd_U16U32(currentDevAddr, (UInt16)(RegAddr), ref RegData);

            //return (ret == 0) ? true : false;
            int DevAddr = devAddr << 1;
            UInt32 rdData = 0;
            UInt32 bfValue = 0;
            int ret = NovoComm.Novo_IIC_Rd_U16U32((byte)DevAddr, (UInt16)RegAddr, ref rdData);
            if (ret != 0)
            {
                return false;
            }

            //Console.WriteLine(string.Format("IIC Read: Reg0x{0} = 0x{1}", RegAddr.ToString("X2"), rdData.ToString("X2")));

            UInt32 bfMask = (UInt32)(Math.Pow(2, endBit + 1) - Math.Pow(2, startBit));

            //Console.WriteLine(((1 << (int)(endBitIx + 1)) - 1).ToString("X2"));
            //Console.WriteLine(((1 << (int)startBitIx) - 1).ToString("X2"));

            //Console.WriteLine(((UInt32)(Math.Pow(2, endBitIx + 1) - 1)).ToString("X2"));
            //Console.WriteLine(((UInt32)(Math.Pow(2, startBitIx) - 1)).ToString("X2"));
            bfValue = (UInt32)((Convert.ToUInt32(rdData) & bfMask) >> (int)startBit);
            RegData = bfValue;

            //Console.WriteLine(string.Format("IIC Read: Reg0x{0} = 0x{1}; BF Mask: 0x{2}\r\n",
            //    RegAddr.ToString("X2"), rdData.ToString("X2"), bfMask.ToString("X2")));


            return true;
        }
        public bool IICRead_Burst(byte devAddr, UInt16 RegAddr, out UInt32[] RegData, int count)
        {
            NovoComm.Novo_SetDeviceId(this.devID);
            RegData = new UInt32[count];
            return false;
        }

        public int IIC_ScanDevAddr(byte[] devAdd)
        {
            //OpenDevice(this.devID);
            NovoComm.Novo_SetDeviceId(this.devID);
            byte[] tempAddrs = new byte[255];
            int devCnt = NovoComm.Novo_IIC_ScanDevAddr(tempAddrs);

            for (int ix = 0; ix < devCnt; ix++)
            {
                devAdd[ix] = tempAddrs[ix];
            }

            return devCnt;
        }

        /// <summary>
        /// Set IIC Mode and Pull EN
        /// </summary>
        /// <param name="i2cMode">0-20K; 1-100K; 2-400K; 3-750K; 4-1M</param>
        /// <param name="PU_En">0: Disable; 1: Enable</param>
        /// <returns></returns>
        public bool IIC_Mode_Set(uint i2cMode, byte PU_En)
        {
            i2c_cfg.ClockSpeedHz = i2cMode;
            i2c_cfg.EnablePu = PU_En;
            int ret = NovoComm.Novo_IIC_Init(ref i2c_cfg);
            Console.WriteLine("Novo_IIC_Init: {0} \n", ret);

            return (ret == 0) ? true : false;
        }

        #endregion I2C for Regmap UI

        #region TestBus API for SerDes Only
        public bool TestBusRead(byte devAddr, UInt16 regAddr_TB, out byte regData_TB)
        {
            /* 0x9050[31:2] - reserved
            * 0x9050[1]    - phy_testclk
            * 0x9050[0]    - phy_testclr
            * 
            * 0x9054[31:17] - reserved
            * 0x9054[16]    - phy_testen
            * 0x9054[15:8]  - phy_testdout
            * 0x9054[7:0]   - phy_testdin
            */

            /* Test bus write method
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x00 //din=0
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * IICSBF 0x9054 [7:0] 0x0C //din= MSB
             * IICSB 0x9050 B1  //clk=1
             * 
             * //Step2, write address 8 bits LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICSB 0x9054 B16 //en=1
             * IICSB 0x9050 B1  //clk=1
             * IICSBF 0x9054 [7:0] 0x0A //din= LSB
             * IICCB 0x9050 B1  //clk = 0
             * IICCB 0x9054 B16 //en=0
             * 
             * //Step3, wirte 8bits data - Do Not Need
             * //IICSBF 0x9054 [7:0] 0x55 //din= data
             * //IICSB 0x9050 B1  //clk=1
             * 
             * //Step4, read 8bits data
             * IICRdBF 0x9054 [15:8]
             */
            int ret = 0;
            UInt16 regAddr_0x9050 = 0x9050;
            UInt16 regAddr_0x9054 = 0x9054;
            UInt32 regData_0x9050 = 0;
            UInt32 regData_0x9054 = 0;
            UInt32 tempData = 0;
            UInt32 mask_B1 = 1 << 1;
            UInt32 mask_B0 = 1;
            UInt32 mask_B16 = 1 << 16;
            UInt32 mask_dout = 0xFF00;
            UInt32 mask_dint = 0xFF;
            regData_TB = 0;

            // Read back Reg0x9050 and Reg0x9054 for bit operations below

            ret = NovoComm.Novo_IIC_Rd_U16U32(this.currentDevAddr, regAddr_0x9050, ref regData_0x9050);
            if (ret != 0) return false;
            ret = NovoComm.Novo_IIC_Rd_U16U32(this.currentDevAddr, regAddr_0x9054, ref regData_0x9054);
            if (ret != 0) return false;

            #region Prepare for testbus access
            /*  IICSB 0x9050 B0
             *  Delay 1
             *  IICCB 0x9050 B0 */
            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) | mask_B0;     // clr = 1
            //ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            //if (ret !=0) return false;

            //Thread.Sleep(1);

            //regData_0x9050 = Convert.ToUInt32(regData_0x9050) & ~mask_B0;     // clr = 0
            //ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            //if (ret !=0) return false;

            #endregion

            #region  Step1
            regData_0x9050 = regData_0x9050 & ~mask_B1;     // clk = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 & ~mask_B16;    // en = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 | mask_B16;    // en = 1
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9050 = regData_0x9050 | mask_B1;     // clk = 1
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 & ~mask_dint;    // din = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9050 = regData_0x9050 & ~mask_B1;     // clk = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 & ~mask_B16;    // en = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9054 = (UInt32)(regData_0x9054 & ~mask_dint) | ((UInt32)(regAddr_TB >> 8) & mask_dint);    // din = targetRegAddr_MSB
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9050 = regData_0x9050 | mask_B1;     // clk = 1
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            #endregion Step1

            #region  Step2
            regData_0x9050 = regData_0x9050 & ~mask_B1;     // clk = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 | mask_B16;    // en = 1
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9050 = regData_0x9050 | mask_B1;     // clk = 1
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = (regData_0x9054) & ~mask_dint | (regAddr_TB & mask_dint);    // din = targetRegAddr_LSB
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            regData_0x9050 = regData_0x9050 & ~mask_B1;     // clk = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, regData_0x9050);
            if (ret != 0) return false;

            regData_0x9054 = regData_0x9054 & ~mask_B16;    // en = 0
            ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, regData_0x9054);
            if (ret != 0) return false;

            #endregion Step2

            #region  Step3 - DO NOT Need
            //tempData = (regData_0x9054) & ~mask_dint) | (sCmd.paramU32[1] & mask_dint);    // din = targetData
            //ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9054, tempData);
            //if (ret !=0) return false;

            //tempData = regData_0x9050) | mask_B1;     // clk = 1
            //ret = NovoComm.Novo_IIC_Wr_U16U32(this.currentDevAddr, regAddr_0x9050, tempData);
            //if (ret !=0) return false;
            #endregion Step3

            #region Step4
            ret = NovoComm.Novo_IIC_Rd_U16U32(this.currentDevAddr, regAddr_0x9054, ref regData_0x9054);
            if (ret != 0) return false;

            tempData = (regData_0x9054 & mask_dout) >> 8;

            regData_TB = (byte)tempData;

            #endregion Step4

            return true;
        }

        #endregion TestBus API for SerDes Only

        public static int EnumDevice()
        {
            totalDevCnt = NovoComm.Novo_EnumDevice();
            return totalDevCnt;
        }

        public bool GPIO_Set(byte mask, byte data)
        {
            return (NovoComm.Novo_GPIO_Set(mask, data) == 0) ? true : false;
        }
    }

    //public enum IICMode
    //{
    //    None = 0,
    //    A8D8 = 0x11,
    //    A8D16 = 0x12,
    //    A8D32 = 0x14,
    //    A16D8 = 0x21,
    //    A16D16 = 0x22,
    //    A16D32 = 0x24,
    //    A32D8 = 0x41,
    //    A32D16 = 0x42,
    //    A32D32 = 0x44
    //}
}